package net.csdn.business.auth.permission;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ArrayUtil;
import lombok.extern.slf4j.Slf4j;
import net.csdn.business.common.domain.request.oauth.OauthAuthPermissionQuery;
import net.csdn.business.common.domain.vo.oauth.OauthAuthPermissionVO;
import net.csdn.business.common.oauth2.service.IOauthAuthPermissionService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.util.AntPathMatcher;

import javax.servlet.http.HttpServletRequest;
import java.util.Collection;
import java.util.List;
import java.util.Set;

/**
 * @Auther: zhangyalei
 * @Date: 2022/11/21 14:39
 * @Description: 自定义获取当前访问的地址需要哪些权限规则
 */
@Slf4j
//@Component
public class UrlFilterInvocationSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {

    /*** ant 路径匹配规则 */
    private final static AntPathMatcher ANT_PATH_MATCHER = new AntPathMatcher();

    @Autowired
    private IOauthAuthPermissionService oauthAuthPermissionService;

    /**
     * 这个是主要的方法，该方法会需要返回url需要的权限列表
     */
    @Override
    public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
        FilterInvocation filterInvocation = (FilterInvocation) object;
        HttpServletRequest request = filterInvocation.getRequest();
        String requestUrl =  request.getRequestURI();
        log.info("请求地址为[{}]", requestUrl);
        String requestMethod =  request.getMethod();
        log.info("请求方式为[{}]", requestMethod);
        // 忽略指定的url
        Set<String> permitSet = permitAll();
        if (CollUtil.isNotEmpty(permitSet)) {
            for (String matcher : permitSet) {
                // 如果当前url和需要忽略的url匹配上就直接返回null，直接放行
                if (ANT_PATH_MATCHER.match(matcher, requestUrl)) {
                    log.info("请求地址为[{}]和忽略规则[{}]匹配，直接放行。", requestUrl, matcher);
                    return null;
                }
            }
        }
        // 根据路径查询路径需要什么权限才能访问
        String[] permissions = findByPath(requestUrl,requestMethod);
        if (ArrayUtil.isNotEmpty(permissions)) {
            log.info("请求地址为[{}]需要权限[{}]", requestUrl, permissions);
            return createList(permissions);
        }
        // 没有匹配上的资源，只要登录就可以访问
        return createList("login");
    }

    @Override
    public Collection<ConfigAttribute> getAllConfigAttributes() {
        return null;
    }

    @Override
    public boolean supports(Class<?> clazz) {
        return FilterInvocation.class.isAssignableFrom(clazz);
    }

    private List<ConfigAttribute> createList(String... attributeNames) {
        return org.springframework.security.access.SecurityConfig.createList(attributeNames);
    }


    /***
     * 该方法用于返回那不需要任何权限就可以访问的路径
     *
     */
    private Set<String> permitAll() {
        return CollUtil.newHashSet();
    }

    /***
     * 该方法用于模拟获取访问指定值地址需要的权限
     * 真实情况下要去数据库中查询，这样便于修改
     * @param requestUrl 请求的地址
     */
    private String[] findByPath(String requestUrl,String method) {
        OauthAuthPermissionQuery query=new OauthAuthPermissionQuery();
        query.setReqMethod(method);
        List<OauthAuthPermissionVO> list=oauthAuthPermissionService.selectOauthRoleList(query);
        String[] result=list.stream().filter(oauthAuthPermissionVO->{
            String reqUrl=oauthAuthPermissionVO.getReqUrl();
            if (ANT_PATH_MATCHER.match(reqUrl, requestUrl)) {
                return true;
            }
            return false;
        }).map(oauthAuthPermissionVO->oauthAuthPermissionVO.getAuthRole()
        ).toArray(String[]::new);
        return result;
    }
}
